// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Constrained_Delaunay_triangulation_2.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Triangulations_2/Py_Constrained_Delaunay_triangulation_2.cpp $
//
// Author(s)     : Naceur Meskini
//=========================================================================

// include ====================================================================
#include <CGAL/basic.h>
#include <include/Kernels.h>
#include <include/iterator.h>

#include <CGAL/Constrained_Delaunay_triangulation_2.h>

#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <CGAL/Triangulation_hierarchy_vertex_base_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>

#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>
#include "Py_Constrained_Delaunay_triangulation_2_doc.h"

// Boost include ==============================================================
#include <boost/python.hpp>
#include <boost/cstdint.hpp>
#include <list>

// Using =======================================================================
using namespace boost::python;

// Declarations ================================================================
namespace  {

	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(insert_overloads_1_2, insert, 1, 2)
	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(is_valid_overloads_0_2, is_valid, 0, 2)

}// namespace 

template < class kernel,class Triangulation>
void py_insert(Triangulation& dt,boost::python::list pts)
{
	typedef typename kernel::Point_2 Point_2;
	for(int i = 0 ; i < pts.attr("__len__")() ; i++)
	{
		Point_2 P = boost::python::extract<Point_2>(pts[i]); 
		dt.insert(P);
	}
}
template <class Constrained_Delaunay,class Point_2>
boost::python::list py_get_conflicts(const Constrained_Delaunay& Cdt,Point_2 pt)
{
	boost::python::list result;
	typedef typename Constrained_Delaunay::Face_handle Face_handle; 
	std::list<Face_handle> liste;
	Cdt.get_conflicts(pt, std::back_inserter(liste));
	typename std::list<Face_handle>::iterator iter;
	for(iter = liste.begin(); iter != liste.end(); iter++)
		result.append(*iter);

	return result;
}


template <class Constrained_Delaunay,class Point_2,class Edge>
boost::python::list py_get_boundary_of_conflicts(const Constrained_Delaunay& Cdt,Point_2 pt)
{
	boost::python::list result;
	std::list<Edge> liste;
	Cdt.get_boundary_of_conflicts(pt, std::back_inserter(liste));
	typename std::list<Edge>::iterator iter;

	for(iter = liste.begin(); iter != liste.end(); iter++)
		result.append(*iter);

	return result;
}
//==============
template <class Constrained_Delaunay,class Point_2,class Face_handle>
boost::python::list py_get_conflicts_2(const Constrained_Delaunay& Cdt,Point_2 pt,Face_handle start)
{
	boost::python::list result;
	std::list<Face_handle> liste;
	Cdt.get_conflicts(pt, std::back_inserter(liste),start);
	typename std::list<Face_handle>::iterator iter;
	for(iter = liste.begin(); iter != liste.end(); iter++)
		result.append(*iter);

	return result;
}


template <class Constrained_Delaunay,class Point_2,class Face_handle,class Edge>
boost::python::list py_get_boundary_of_conflicts_2(const Constrained_Delaunay& Cdt,Point_2 pt,Face_handle start)
{
	boost::python::list result;
	std::list<Edge> liste;
	Cdt.get_boundary_of_conflicts(pt, std::back_inserter(liste),start);
	typename std::list<Edge>::iterator iter;

	for(iter = liste.begin(); iter != liste.end(); iter++)
		result.append(*iter);

	return result;
}

// template<class Constraint>
// struct std_list_from_python_list
// {
// 	typedef std::list<Constraint> constraint_list;
// 	std_list_from_python_list()
// 	{
// 		boost::python::converter::registry::push_back(&convertible,&construct,boost::python::type_id<constraint_list>());
// 	}
// 
// 	static void* convertible(PyObject* obj_ptr)
// 	{
// 		if (!PyList_Check(obj_ptr)) return 0;
// 		return obj_ptr;
// 	}
// 	
// 	static void construct(PyObject* obj_ptr,boost::python::converter::rvalue_from_python_stage1_data* data)
// 	{
// 		int value = PyList_Check(obj_ptr);
// 		if (value == 0) boost::python::throw_error_already_set();
// 		constraint_list liste;
// 		int lenth = PyList_Size(obj_ptr);
// 		for(int i=0; i < lenth ;i++)liste.push_back(boost::python::extract<Constraint>( PyList_GetItem(obj_ptr,i) ) ); 
// 		void* storage = ( (boost::python::converter::rvalue_from_python_storage<constraint_list>*)data)->storage.bytes;
// 		new (storage)constraint_list(liste);
// 		data->convertible = storage;
// 	}
// };

// exporting function ======================================================================
template <class kernel>
void Py_Constrained_Delaunay_triangulation_2()
{
	// three things must be fixed in order to insure the derivation in the python side.
	// -1: the vertex_base 
	// -2: the face_base
	// -3: the data_structure
	typedef CGAL::Alpha_shape_vertex_base_2<kernel> 	Avb;
	typedef CGAL::Triangulation_hierarchy_vertex_base_2<Avb> Hv; //this one is needed when the input data set is huge for the Alpha_shape_2,
																 // say more than 10.000 points,
	typedef CGAL::Triangulation_vertex_base_with_info_2<boost::python::object,kernel,Hv> 	Vb;

	typedef CGAL::Delaunay_mesh_face_base_2<kernel> 	Mf; 
	typedef CGAL::Alpha_shape_face_base_2<kernel,Mf> 	Af;

	typedef CGAL::Triangulation_data_structure_2<Vb,Af> Tds;

	typedef CGAL::Triangulation_2<kernel,Tds>   										Triangulation_2;
	typedef typename Triangulation_2::Edge 												Edge;
	typedef typename Triangulation_2::Face 												Face;

	typedef CGAL::Exact_predicates_tag 													Exact_predicates_tag;
	typedef CGAL::Constrained_triangulation_2<kernel,Tds,Exact_predicates_tag>   		Constrained_triangulation_2;
	typedef typename Constrained_triangulation_2::Constraint							Constraint;

	typedef CGAL::Constrained_Delaunay_triangulation_2<kernel,Tds,Exact_predicates_tag>   Constrained_Delaunay_triangulation_2;

	typedef typename Constrained_Delaunay_triangulation_2::Face_handle 					Face_handle;
	typedef typename Constrained_Delaunay_triangulation_2::Vertex_handle 				Vertex_handle;

	typedef typename Triangulation_2::Locate_type 										Locate_type;
	typedef typename kernel::Point_2 													Point_2;
	typedef typename std::list<Face_handle>::iterator  OutputItFaces;
	typedef typename std::list<Edge>::iterator  OutputItEdges;

// 	std_list_from_python_list<Constraint>();

    class_< Constrained_Delaunay_triangulation_2, bases< Constrained_triangulation_2 > >("Constrained_Delaunay_triangulation_2",Constrained_Delaunay_triangulation_2_doc, init< optional< const kernel& > >())
        .def(init< const Constrained_Delaunay_triangulation_2& >(cdt_init_doc))
        .def(init< std::list<Constraint,std::allocator<Constraint > >&, optional< const kernel& > >()) // to be modified.
        .def("is_flipable", &Constrained_Delaunay_triangulation_2::is_flipable,cdt_is_flipable_doc)
        .def("flip", &Constrained_Delaunay_triangulation_2::flip,cdt_flip_doc)
        .def("propagating_flip", (void (Constrained_Delaunay_triangulation_2::*)(std::list<Edge>&) )&Constrained_Delaunay_triangulation_2::propagating_flip,cdt_propagating_flip_doc) // to be transformed to take python-list

		.def("insert", (Vertex_handle (Constrained_Delaunay_triangulation_2::*)(const Point_2&, Face_handle) )&Constrained_Delaunay_triangulation_2::insert, insert_overloads_1_2(cdt_insert_doc))
		.def("insert", (Vertex_handle (Constrained_Delaunay_triangulation_2::*)(const Point_2&, Locate_type, Face_handle, int) )&Constrained_Delaunay_triangulation_2::insert)
		.def("insert",&py_insert<kernel,Constrained_Delaunay_triangulation_2>)

        .def("push_back", &Constrained_Delaunay_triangulation_2::push_back,cdt_push_back_doc)
        .def("remove", &Constrained_Delaunay_triangulation_2::remove,cdt_remove_doc)
        .def("remove_incident_constraints", &Constrained_Delaunay_triangulation_2::remove_incident_constraints,cdt_remove_incident_constraints_doc)
		.def("remove_constrained_edge",(void (Constrained_Delaunay_triangulation_2::*)(Face_handle, int ))&Constrained_Delaunay_triangulation_2::remove_constrained_edge,cdt_remove_constrained_edge_doc)
        .def("insert", (void (Constrained_Delaunay_triangulation_2::*)(Point_2, Point_2) )&Constrained_Delaunay_triangulation_2::insert)
        .def("insert", (void (Constrained_Delaunay_triangulation_2::*)(Vertex_handle, Vertex_handle) )&Constrained_Delaunay_triangulation_2::insert)
        .def("remove_constraint", &Constrained_Delaunay_triangulation_2::remove_constraint,cdt_remove_constraint_doc)
        .def("is_valid", &Constrained_Delaunay_triangulation_2::is_valid, is_valid_overloads_0_2(cdt_is_valid_doc))
		.def("get_conflicts",&py_get_conflicts<Constrained_Delaunay_triangulation_2,Point_2>,cdt_get_conflicts_doc)
		.def("get_boundary_of_conflicts",&py_get_boundary_of_conflicts<Constrained_Delaunay_triangulation_2,Point_2,Edge>,cdt_get_boundary_of_conflicts_doc)
// 		.def("get_conflicts",&py_get_conflicts<Constrained_Delaunay_triangulation_2,Point_2,Face_handle>,cdt_get_conflicts_doc)
// 		.def("get_boundary_of_conflicts",&py_get_boundary_of_conflicts<Constrained_Delaunay_triangulation_2,Point_2,Face_handle,Edge>,cdt_get_boundary_of_conflicts_doc)    
// 	
	;
}

void export_Constrained_Delaunay_triangulation_2()
{
	Py_Constrained_Delaunay_triangulation_2<K>();
}
